package tech.yixiyun.framework.kuafu.domain;


import tech.yixiyun.framework.kuafu.domain.annotation.Domain;
import tech.yixiyun.framework.kuafu.domain.annotation.DomainType;
import tech.yixiyun.framework.kuafu.domain.annotation.Key;
import tech.yixiyun.framework.kuafu.domain.annotation.KeyType;

import java.lang.reflect.Field;
import java.util.*;

/**
 * Domain类定义
 */
public class DomainDefinition {

    /**
     * 对应哪个数据来源
     */
    private String dataSource;

    /**
     * 对应的是表还是视图，如果是视图，那么创建表结构时会跳过该类
     */
    private DomainType type;

    /**
     * 是否是分表
     */
    private boolean isSplit;

    /**
     * 分表表名命名规则
     */
    private String splitRule;

    /**
     * 表名
     */
    private String tableName;

    /**
     * 表对应的实体Domain类
     */
    private Class domainClass;


    /**
     * 表使用的字符集
     */
    private String charset;

    /**
     * 表注释
     */
    private String comment;

    /**
     * 表上所有的索引定义
     */
    private List<KeyDefinition> keys;

    /**
     * 表里所有的列,key就是列名，value就是类中对应的字段
     */
    private Map<String, ColumnDefinition> columnMap = new LinkedHashMap<>();

    /**
     * 需要自增的字段
     */
    private String autoIncrementColumn;


    /**
     * 单表Domain类定义
     * @param clazz
     */
    public DomainDefinition(Class clazz) {
        this.domainClass = clazz;
        Domain domain = (Domain) domainClass.getAnnotation(Domain.class);
        if (domain == null) {
            throw new DomainException(clazz.getName() + "未检测到@Domain注解，无法在DomainContext中注册");
        }
        if ("".equals(domain.tableName())) { //没指定表名就默认用类名
            this.tableName = clazz.getSimpleName().toLowerCase();
        } else  {
            this.tableName = domain.tableName();
        }
        this.dataSource = domain.dataSource();
        this.type = domain.type();
        this.charset = domain.charset();
        this.comment = domain.comment();
        //表名中包含*号，自动识别为分表
        if (this.tableName.contains("*")) {
            this.isSplit =true;
            this.splitRule = this.tableName;
        }
        if (domain.keys().length > 0) {
            for (Key key : domain.keys()) {
                this.addKey(new KeyDefinition(key));
            }
        }
    }



    /**
     * 添加列定义
     * @param column
     */
    public void addColumn(ColumnDefinition column) {
        this.columnMap.put(column.getName(), column);
    }

    /**
     * 添加索引定义
     * @param key
     */
    public void addKey(KeyDefinition key) {
        if (this.keys == null) {
            this.keys = new ArrayList<KeyDefinition>();
        }
        this.keys.add(key);
    }



    public boolean getIsSplit() {
        return isSplit;
    }


    public String getSplitRule() {
        return splitRule;
    }

    public String getTableName() {
        return tableName;
    }


    public Class getDomainClass() {
        return domainClass;
    }




    public String getCharset() {
        return charset;
    }


    public String getComment() {
        return comment;
    }

    /**
     * 主键的列名
     * @return
     */
    public String[] getPrimaryKeyColumns() {
        for (KeyDefinition key : getKeys()) {
            if (key.getType() == KeyType.PRIMARY) {
                return key.getColumns();
            }
        }
        return null;
    }

    /**
     * 获得主键字段名
     * @return
     */
    public Field[] getPrimaryKeyFields() {
        String[] names = getPrimaryKeyColumns();
        if (names == null || names.length == 0) {
            return null;
        }
        Field[] fields = new Field[names.length];
        for (int i = 0; i < names.length; i++) {
            String name = names[i];
            fields[i] = columnMap.get(name).getField();
        }
        return fields;
    }
    /**
     * 获得主键字段的定义
     * @return
     */
    public ColumnDefinition[] getPrimaryKeyColDefinitions() {
        String[] names = getPrimaryKeyColumns();
        if (names == null || names.length == 0) {
            return null;
        }
        ColumnDefinition[] fields = new ColumnDefinition[names.length];
        for (int i = 0; i < names.length; i++) {
            String name = names[i];
            fields[i] = columnMap.get(name);
        }
        return fields;
    }

    public List<KeyDefinition> getKeys() {
        return this.keys == null ? Collections.emptyList() : new ArrayList<>(this.keys);
    }


    public Map<String, ColumnDefinition> getColumnMap() {
        return new LinkedHashMap<>(columnMap);
    }

    /**
     * 根据数据库的列名查询对应的列定义
     * @param columnName
     * @return
     */
    public ColumnDefinition getColumn(String columnName) {
        return columnMap.get(columnName);
    }

    /**
     * 获取所有的普通列定义List，即不包含isTemp=true的列
     * @return
     */
    public List<ColumnDefinition> getNormalColumnList() {
        List<ColumnDefinition> result = new ArrayList<>();
        columnMap.values().forEach(item -> {
            if (item.getIsTemp() == false) {
                result.add(item);
            }
        });
        return result;
    }
    /**
     * 获取所有的列定义List
     * @return
     */
    public List<ColumnDefinition> getAllColumnList() {
        return new ArrayList<>(columnMap.values());
    }

    public DomainType getType() {
        return type;
    }

    public String getAutoIncrementColumn() {
        return autoIncrementColumn;
    }

    void setAutoIncrementColumn(String autoIncrementColumn) {
        this.autoIncrementColumn = autoIncrementColumn;
    }

    public String getDataSource() {
        return dataSource;
    }

    public void setDataSource(String dataSource) {
        this.dataSource = dataSource;
    }
}
